﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Text.RegularExpressions;
using DBCodeBuilder.Core.Enum;
using DBCodeBuilder.Core.Interfaces;
using HSystem.Data.Core.Enum;

namespace DBCodeBuilder.Core.Classes
{
    public static class Utility
    {
        internal static DbHType ParseType(string type, int? dataPrecision, int? dataScale)
        {
            switch (type)
            {
                case "CLOB":
                    return DbHType.StringUnlimited;
                case "BLOB":
                    return DbHType.Binary;
                case "DATE":
                    return DbHType.DateTime;
                case "VARCHAR2":
                case "CHAR":
                    return DbHType.String;
                case "FLOAT":
                    return DbHType.Double;
                case "NUMBER":
                    if (!dataPrecision.HasValue)
                    {
                        if (!dataScale.HasValue || dataScale.Value != 0)
                            return DbHType.Decimal;

                        return DbHType.Int32;
                    }
                    if (dataPrecision.Value > 9)
                        return DbHType.Int64;
                    if (dataPrecision.Value > 4)
                        return DbHType.Int32;
                    return DbHType.Int16;
                case "INTEGER":
                case "PLS_INTEGER":
                    return DbHType.Int32;
                default:
                    throw new Exception("Errore type " + type);
            }
        }

        internal static string GetCSType(DbHType type, bool nullable)
        {
            switch (type)
            {
                case DbHType.String:
                case DbHType.StringUnlimited:
                    return "string";
                case DbHType.Binary:
                    return "byte[]";
                case DbHType.Date:
                case DbHType.DateTime:
                    return nullable ? "DateTime?" : "DateTime";
                case DbHType.Decimal:
                    return nullable ? "decimal?" : "decimal";
                case DbHType.Int16:
                    return nullable ? "short?" : "short";
                case DbHType.Int32:
                    return nullable ? "int?" : "int";
                case DbHType.Int64:
                    return nullable ? "long?" : "long";
                case DbHType.Double:
                    return nullable ? "double?" : "double";
                case DbHType.Complex:
                    return "object";
                default:
                    throw new Exception("Errore type " + type);
            }
        }

        internal static string GetConvertFunc(DbHType type)
        {
            switch (type)
            {
                case DbHType.Date:
                case DbHType.DateTime:
                    return "ToDateTime";
                case DbHType.Int64:
                    return "ToInt64";
                case DbHType.Int32:
                    return "ToInt32";
                case DbHType.Int16:
                    return "ToInt16";
                case DbHType.StringUnlimited:
                case DbHType.String:
                    return "ToString";
                case DbHType.Double:
                    return "ToDouble";
                default:
                    throw new Exception("Errore type " + type);
            }
        }

        public static void DispatchObjects(List<IDbObjectModel> toDispatch, out List<IDbObjectModel> tables, out List<IDbObjectModel> views)
        {
            tables = new List<IDbObjectModel>();
            views = new List<IDbObjectModel>();

            foreach (var model in toDispatch)
            {
                switch (model.ObjectType)
                {
                    case DbObjectType.Table:
                        tables.Add(model);
                        break;
                    case DbObjectType.View:
                        views.Add(model);
                        break;
                }
            }
        }

        public static string CompressString(string str)
        {
            var bytes = Encoding.UTF8.GetBytes(str);

            using (var msi = new MemoryStream(bytes))
            using (var mso = new MemoryStream())
            {
                using (var gs = new GZipStream(mso, CompressionMode.Compress))
                    msi.CopyTo(gs);

                return Convert.ToBase64String(mso.ToArray());
            }
        }

        public static string DecompressString(string b64Bytes)
        {
            var bytes = Convert.FromBase64String(b64Bytes);
            using (var msi = new MemoryStream(bytes))
            using (var mso = new MemoryStream())
            {
                using (var gs = new GZipStream(msi, CompressionMode.Decompress))
                    gs.CopyTo(mso);

                return Encoding.UTF8.GetString(mso.ToArray());
            }
        }

        public static bool IsBase64String(this string s)
        {
            s = s.Trim();
            return (s.Length % 4 == 0) && Regex.IsMatch(s, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None);
        }
    }
}